package com.isotne.glidelibrary.utils;

import com.isotne.glidelibrary.FileType;
import com.isotne.glidelibrary.cache.util.DiskLruCacheImpl;
import com.isotne.glidelibrary.cache.util.MemoryCacheUtil;
import com.isotne.glidelibrary.constant.Constents;
import com.isotne.glidelibrary.gif.LoadGif;
import com.isotne.glidelibrary.okhttp.OkHttpManager;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Image;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

import java.io.*;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import javax.imageio.*;
import javax.imageio.stream.*;

/**
 * description 鸿蒙 Glide 组件
 *
 * @author baihe
 * created 2021/2/8 11:54
 */
public class OhosGlide {
    /**
     * abilitySlice
     */
    private AbilitySlice abilitySlice;
    /**
     * url 图片地址
     */
    private String url = null;
    /**
     * inputstream
     */
    private InputStream inputStream;

    private  byte[] bytes;

    /**
     * default imager resources id
     */
    private int defImage;
    /**
     * iamge
     */
    private Image image;
    /**
     * whole image
     */
    private PixelMap pixelMap;
    /**
     * file  type
     */
    private FileType fileType;
    /**
     * isGIf
     */
    private boolean isGif=false;

    /**
     * diskLruCacheImpl
     */
    private DiskLruCacheImpl diskLruCacheImpl;
    /**
     * pixelmap list
     */
    private List<PixelMap> pixelMapList = new ArrayList<>();
    /**
     * animatorvalue
     */
    private AnimatorValue animatorValue;

    /**
     * init disk
     *
     * @param ability
     * @throws IOException
     */
    public OhosGlide(AbilitySlice ability) throws IOException {
        this.abilitySlice = ability;
        if (diskLruCacheImpl == null) {
            diskLruCacheImpl =
                    new DiskLruCacheImpl(abilitySlice.getExternalCacheDir().toString() + "/" + Constents.DISK_CACHE_PATH);

        }

    }



    /**
     * init glide
     *
     * @param ability ability
     * @return OhosGlide
     * @throws IOException IOException
     */
    public static OhosGlide with(AbilitySlice ability) throws IOException {

        return new OhosGlide(ability);
    }

    /**
     * load url
     *
     * @param url url
     * @return OhosGlide
     */
    public OhosGlide load(String url) {
        this.url = url;

        return this;
    }

    /**
     * load asset 资源图片
     * @param resourceid
     * @return
     */
    public OhosGlide load(int resourceid) throws Exception {
        InputStream inputStream=null;
        try {
            inputStream = abilitySlice.getContext().getResourceManager().getResource(resourceid);
            bytes = new byte[inputStream.available()];
            this.url=String.valueOf(resourceid);
            inputStream.read(bytes);
            this.inputStream=new ByteArrayInputStream(bytes);

        } catch (Exception e) {
           throw  e;
        }
        return this;
    }
    private static boolean isGIF(byte[] buf) {

        byte[] markBuf = "GIF89a".getBytes(); //GIF识别符
        if(compare(buf, markBuf))
        {
            return true;
        }
        markBuf = "GIF87a".getBytes(); //GIF识别符
        if(compare(buf, markBuf))
        {
            return true;
        }
        return false;
    }

    /**
     * 标示一致性比较
     * @param buf  待检测标示
     * @param markBuf 标识符字节数组
     * @return 返回false标示标示不匹配
     */
    private static boolean compare(byte[] buf, byte[] markBuf) {
        for (int i = 0; i < markBuf.length; i++) {
            byte b = markBuf[i];
            byte a = buf[i];

            if(a!=b){
                return false;
            }
        }
        return true;
    }
    private static byte[] readInputStreamAt(byte[] fis, long skiplength, int length) throws IOException
    {
        byte[] buf = new byte[8];

        System.arraycopy(fis,0,buf,0,8);
        return buf;
    }



    /**
     * 设置默认图片，当发生异常时使用
     *
     * @param defImage defImage
     * @return OhosGlide
     */
    public OhosGlide def(int defImage) {
        this.defImage = defImage;
        return this;
    }

    /**
     * if set cache
     *
     * @param isDiskCache isDiskCache
     * @return OhosGlide
     */
    public OhosGlide hasDiskCache(boolean isDiskCache) {
        return this;
    }

    /**
     * 需要渲染的iamge
     *
     * @param image image
     */
    public void into(Image image) throws IOException {
        this.image = image;
        boolean hasCache=false;
        {

            hasCache = MemoryCacheUtil.isCache(url);
            if (hasCache) {//内存有缓存

                bytes = MemoryCacheUtil.getPixelMap(url);
                inputStream=new ByteArrayInputStream(bytes);

            } else {
                hasCache=diskLruCacheImpl.isCache(url);
                if (hasCache) {//磁盘有缓存

                    bytes = diskLruCacheImpl.getDiskCache(url);
                    inputStream=new ByteArrayInputStream(bytes);
                }

            }


        }
        if(bytes!=null&&bytes.length>0)
        {
            isGif=isGIF(bytes);
            if (isGif) {
                showGif(inputStream);
            }
            else {
                showImage(bytes);
            }
        }
        else{
            if(this.url.indexOf("http")>=0){

                downLoadFile();

            }
        }

    }

    /**
     * downLoadFile
     */
    public void downLoadFile() {


        OkHttpManager.getInstance().asyncGet(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

                byte[] bytes = diskLruCacheImpl.getDiskCache(url);
                if (bytes != null) {

                    inputStream=new ByteArrayInputStream(bytes);
                    isGif=isGIF(bytes);
                    if (isGif) {
                        showGif(inputStream);
                    }
                    else {
                        showImage(bytes);
                    }


                } else {
                    abilitySlice.getUITaskDispatcher().asyncDispatch(() -> {
                        image.setPixelMap(defImage);
                    });
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                byte[] bytes = response.body().bytes();
                inputStream=new ByteArrayInputStream(bytes);
                isGif=isGIF(bytes);
                if (response.isSuccessful()) {
                   if (isGif) {
                        showGif(inputStream);
                    }
                   else{
                       showImage(bytes);
                   }
                    inputStream.close();
                    diskLruCacheImpl.addDiskCache(bytes, url);
                }
            }
        }, url);

    }

    /**
     * 展示网络图片
     *
     * @param bytes bytes
     */
    private void showImage(byte[] bytes) {

        ImageSource imageSource = ImageSource.create(bytes, new ImageSource.SourceOptions());
        pixelMap = imageSource.createPixelmap(new ImageSource.DecodingOptions());

        /**添加缩略图
         ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
         PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false);
         **/

        abilitySlice.getUITaskDispatcher().asyncDispatch(() -> {

            image.setPixelMap(pixelMap);

            MemoryCacheUtil.savePixelMap(url, bytes);


        });
    }


    /**
     * 展示gif
     */
    private int index = 0;

    /**
     *
     * @param inputStream inputStream
     */
    private void showGif(InputStream inputStream) {

        ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        decodingOpts.allowPartialImage = true;
        sourceOptions.formatHint = "image/gif";
        ImageSource imageSource = ImageSource.create(inputStream, sourceOptions);

        try{

            if (imageSource != null) {
                index = 0;
                while (imageSource.createPixelmap(index, decodingOpts) != null) {
                    pixelMapList.add(imageSource.createPixelmap(index, decodingOpts));
                    index++;
                }
            }

        }
        catch (Exception ee){

            System.out.println(ee.getMessage());

        }

        // start anim
        abilitySlice.getUITaskDispatcher().asyncDispatch(() -> {
            LoadGif.loadGif(abilitySlice, pixelMapList, image, index);
        });
    }


    /**
     * 展示本地图片
     *
     * @param inputStream inputStream
     */
    private void setLoalImage(InputStream inputStream) {
        ImageSource imageSource = ImageSource.create(inputStream, new ImageSource.SourceOptions());
        PixelMap pixelMap = imageSource.createPixelmap(new ImageSource.DecodingOptions());
        abilitySlice.getUITaskDispatcher().asyncDispatch(() -> {
            image.setPixelMap(pixelMap);
        });
    }

    /**
     * 将inputstream 转换为图片
     *
     * @param path        path
     * @param inputStream inputStream
     */
    private void convertToFile(String path, InputStream inputStream) {
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir, "test.png");

        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            try {
                byte[] b = new byte[1024];
                int n;
                while ((n = inputStream.read(b)) != -1) {
                    outputStream.write(b, 0, n);
                }
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }





}


